#include "DS1302.h"

#define DS1302_REG_SECONDS  0x80
#define DS1302_REG_MINUTES  0x82
#define DS1302_REG_HOURS    0x84
#define DS1302_REG_DATES    0x86
#define DS1302_REG_MONTHS   0x88
#define DS1302_REG_DAYS     0x8A
#define DS1302_REG_YEARS    0x8C
#define DS1302_REG_WP       0x8E

static ds1302_gpio_ops_t gpio_ops = {0};

// 注册GPIO操作函数
int ds1302_set_gpio_ops(const ds1302_gpio_ops_t *ops)
{
    if (!ops) return -1;
    gpio_ops = *ops;
    return 0;
}

static uint8_t val_to_bcd(uint8_t val)
{
    return (val / 10 * 16 + val % 10);
}

static uint8_t bcd_to_dec(uint8_t bcd)
{
    return (10 * (bcd>>4) + (bcd & 0x0F));
}

// 写寄存器
static void ds1302_write_reg(uint8_t reg, uint8_t dat)
{
    gpio_ops.ce_high();
    gpio_ops.sclk_low(); 
    reg = reg & 0xFE; // 确保最低位为0
    for (int i = 0; i < 8; i++) {
        if (reg & 0x01)
            gpio_ops.io_high();
        else
            gpio_ops.io_low();
        gpio_ops.sclk_high();
        reg >>= 1;
        gpio_ops.sclk_low();
    }
    for (int i = 0; i < 8; i++) {
        if (dat & 0x01)
            gpio_ops.io_high();
        else
            gpio_ops.io_low();
        gpio_ops.sclk_high();
        dat >>= 1;
        gpio_ops.sclk_low();
    }
    gpio_ops.ce_low();
}

// 读寄存器
static uint8_t ds1302_read_reg(uint8_t reg)
{
    uint8_t dat = 0;
    reg = reg | 0x01; // 确保最低位为1
    gpio_ops.sclk_low();
    gpio_ops.ce_high();
    for (int i = 0; i < 8; i++) {
        gpio_ops.sclk_low();
        if (reg & 0x01)
            gpio_ops.io_high();
        else
            gpio_ops.io_low();
        gpio_ops.sclk_high();
        reg >>= 1;
    }
    gpio_ops.io_in();
    for (int i = 0; i < 8; i++) {
        gpio_ops.sclk_low();
        if (gpio_ops.io_read())
            dat |= (1 << i); 
        if (i < 7)
            gpio_ops.sclk_high();
    }
    gpio_ops.io_out();
    gpio_ops.ce_low();
    return dat;
}

int ds1302_init(void)
{
/* 自定义内容 */
}

int ds1302_get_time(struct tm *time_struct)
{
    ds1302_reg_type reg;
    reg.Seconds  = ds1302_read_reg(DS1302_REG_SECONDS);
    reg.Minutes  = ds1302_read_reg(DS1302_REG_MINUTES);
    reg.Hours    = ds1302_read_reg(DS1302_REG_HOURS);
    reg.Dates    = ds1302_read_reg(DS1302_REG_DATES);
    reg.Months   = ds1302_read_reg(DS1302_REG_MONTHS);
    reg.Days     = ds1302_read_reg(DS1302_REG_DAYS);
    reg.Years    = ds1302_read_reg(DS1302_REG_YEARS);

    time_struct->tm_sec  = bcd_to_dec(reg.Seconds);
    time_struct->tm_min  = bcd_to_dec(reg.Minutes);
    time_struct->tm_hour = bcd_to_dec(reg.Hours);
    time_struct->tm_mday = bcd_to_dec(reg.Dates);
    time_struct->tm_mon  = bcd_to_dec(reg.Months) - 1;
    time_struct->tm_year = 2000 + bcd_to_dec(reg.Years) - 1900;
    time_struct->tm_wday = bcd_to_dec(reg.Days); 

    return 0;
}

int ds1302_set_time(struct tm *time_struct)
{
    ds1302_reg_type reg;
    reg.Seconds  = val_to_bcd(time_struct->tm_sec);
    reg.Minutes  = val_to_bcd(time_struct->tm_min);
    reg.Hours    = val_to_bcd(time_struct->tm_hour);
    reg.Dates    = val_to_bcd(time_struct->tm_mday);
    reg.Months   = val_to_bcd(time_struct->tm_mon + 1);
    reg.Days     = val_to_bcd(time_struct->tm_wday); 
    reg.Years    = val_to_bcd(time_struct->tm_year - 2000 + 1900);

    ds1302_write_reg(DS1302_REG_WP, 0x00);// 关闭写保护
    ds1302_write_reg(DS1302_REG_MINUTES, reg.Minutes);
    ds1302_write_reg(DS1302_REG_HOURS, reg.Hours);
    ds1302_write_reg(DS1302_REG_DATES, reg.Dates);
    ds1302_write_reg(DS1302_REG_MONTHS, reg.Months);
    ds1302_write_reg(DS1302_REG_DAYS, reg.Days);
    ds1302_write_reg(DS1302_REG_YEARS, reg.Years);
    ds1302_write_reg(DS1302_REG_SECONDS, reg.Seconds);
    ds1302_write_reg(DS1302_REG_WP, 0x80);

    return 0;
}